﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.Remoting;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace Dazzle {
    [Guid("ACEB0888-1EE6-4b06-836F-1E0BE444F34D"),
    ClassInterface(ClassInterfaceType.None)]
    public class ExamplePropertyPage : IPropertyPage {
        IPropertyPageSite m_pPageSite = null;
        object[] m_pObjects = null;

        [DllImport("User32.dll", ExactSpelling = true, CharSet = CharSet.Auto)]
        public extern static IntPtr SetParent(IntPtr hWnd, IntPtr hWndParent);

        PropertyGrid m_pPage;

        #region IPropertyPage Members

        public void Activate(IntPtr hWndParent, ref Win32.RECT pRect, bool bModal) {
            m_pPage = new PropertyGrid();
            m_pPage.CreateControl();
            SetParent(m_pPage.Handle, hWndParent);

            m_pPage.Width = pRect.Right - pRect.Left;
            m_pPage.Height = pRect.Bottom - pRect.Top;
            m_pPage.Left = pRect.Left;
            m_pPage.Top = pRect.Top;

            if (m_pObjects[0] is GraphBox) {
                GraphBox control = m_pObjects[0] as GraphBox;
                if (control != null)
                    m_pPage.SelectedObject = control.Chart;
            } 
        }

        public void Apply() {
            if (m_pObjects[0] is GraphBox) {
                GraphBox control = m_pObjects[0] as GraphBox;
                control.Chart = m_pPage.SelectedObject as ZedGraph.ZedGraphControl;
            }
        }

        public void Deactivate() {
        }

        public void GetPageInfo(ref Win32.PROPPAGEINFO pPageInfo) {
            pPageInfo.cb = (UInt32)Marshal.SizeOf(typeof(Win32.PROPPAGEINFO));
            pPageInfo.pszTitle = Marshal.StringToCoTaskMemUni("Bitmap Effects");
            pPageInfo.pszDocString = Marshal.StringToCoTaskMemUni("Example Property Page for PB IDE");
            pPageInfo.pszHelpFile = IntPtr.Zero;
            pPageInfo.size.cx = 300;
            pPageInfo.size.cy = 300;

        }

        public void Help(string pszHelpDir) {
            throw new NotImplementedException();
        }

        public int IsPageDirty() {
            throw new NotImplementedException();
        }

        public void Move(ref Win32.RECT pRect) {
            throw new NotImplementedException();
        }

        public void SetObjects(uint cObjects, [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.IUnknown, SizeParamIndex = 0)] object[] ppunk) {
            if (m_pObjects != null) {
                for (int c = 0; c < m_pObjects.Length; ++c) {
                    if (Marshal.IsComObject(m_pObjects[c])) {
                        Marshal.ReleaseComObject(m_pObjects[c]);
                    }
                    m_pObjects[c] = null;
                }
            }
            m_pObjects = ppunk;

        }

        public void SetPageSite(IPropertyPageSite pPageSite) {
            if (m_pPageSite != null) {
                if (Marshal.IsComObject(m_pPageSite)) {
                    Marshal.ReleaseComObject(m_pPageSite);
                }
            }
            m_pPageSite = pPageSite;
        }

        public void Show(uint nCmdShow) {
            if (nCmdShow == 0)
                m_pPage.Visible = false;
            else
                m_pPage.Visible = true;
        }

        public int TranslateAccelerator(ref Message pMsg) {
            m_pPage.PreProcessMessage(ref pMsg);
            return 1;
        }

        #endregion
    }

    //[Guid("2E061368-B56F-4501-9F38-9EB12F3E148E")]
    //[ClassInterface(ClassInterfaceType.None)]
    public class PropertyPage : IPropertyPage {
        private ILog logger = LogManager.GetLogger(typeof(PropertyPage));

        PropertyGrid _grid;
        IPropertyPageSite _site;
        bool _isDirty;
        bool _isActivating;
        IntPtr _hwndOrigParent;
        UInt32 _origStyle;
        object[] _objects;

        //void OnPageActivate(IntPtr hWndParent, Win32.RECT Rect, bool bModal) { }

        #region IPropertyPage Members

        public void SetPageSite(IPropertyPageSite pPageSite) {
            logger.Debug("PropertyPage SetPageSite()");

            if (_site != null) {
                if (Marshal.IsComObject(_site)) {
                    while (Marshal.ReleaseComObject(_site) != 0)
                        ;
                }
            }

            _site = pPageSite;
        }

        public void Activate(IntPtr hWndParent, ref Win32.RECT pRect, bool bModal) {
            logger.Debug("PropertyPage Activate()");

            _isActivating = true;
            _grid.Left = 0;
            _grid.Top = 0;

            _hwndOrigParent = Win32.SetParent(_grid.Handle, hWndParent);


            UInt32 n = Win32.GetWindowLong32(_grid.Handle, Constants.GWL_STYLE);

            _origStyle = n;

            // Disable the following styles:
            // WS_POPUP | WS_CHILD | WS_MINIMIZE | WS_VISIBLE | WS_MAXIMIZE |
            // WS_CAPTION | WS_BORDER | WS_DLGFRAME | WS_SYSMENU | WS_THICKFRAME |
            // WS_MINIMIZEBOX | WS_MAXIMIZEBOX
            n &= ~0xF1CF0000;

            // Enable WS_CHILD
            n |= Constants.WS_CHILD;

            Win32.SetWindowLong(_grid.Handle, Constants.GWL_STYLE, (int)n);
            OnPageActivate(hWndParent, pRect, bModal);

            
            _isActivating = false;
        }

        public void Deactivate() {
            logger.Debug("PropertyPage Deactivate()");

            Win32.SetWindowLong(_grid.Handle, Constants.GWL_STYLE, (int)_origStyle);
            Win32.SetParent(_grid.Handle, _hwndOrigParent);

            OnPageDeactivate();
            _grid.Dispose();
            //Close();
        }

        public void GetPageInfo(ref Win32.PROPPAGEINFO pPageInfo) {
            logger.Debug("PropertyPage GetPageInfo()");

            pPageInfo.cb = (UInt32)Marshal.SizeOf(typeof(Win32.PROPPAGEINFO));
            pPageInfo.pszTitle = Marshal.StringToCoTaskMemUni("Bitmap Effects");
            pPageInfo.pszDocString = Marshal.StringToCoTaskMemUni("DocString");//!string.IsNullOrEmpty(this.Text) ? Marshal.StringToCoTaskMemUni(Text) : IntPtr.Zero;
            pPageInfo.pszHelpFile = Marshal.StringToCoTaskMemUni("Help File");

            pPageInfo.size.cx = _grid.Width;
            pPageInfo.size.cy = _grid.Height;
        }

        public void SetObjects(uint cObjects, object[] ppunk) {
            logger.Debug("PropertyPage SetObjects()");

            //IProvideObjectHandle poh = null;
            //ObjectHandle objhandle = null;
            //Object po = null;

            //if (_objects != null) {
            //    for (int n = 0; n < _objects.Length; n++) {
            //        if (_objects[n] != null) {
            //            if (Marshal.IsComObject(_objects[n])) {
            //                while (Marshal.ReleaseComObject(_objects[n]) != 0)
            //                    ;
            //            }

            //            _objects[n] = null;
            //        }
            //    }
            //}

            //_objects = ppunk;

            //if (_objects != null) {
            //    for (int n = 0; n < _objects.Length; n++) {
            //        if (_objects[n] != null) {
            //            if (Marshal.IsComObject(_objects[n])) {
            //                try {
            //                    poh = (IProvideObjectHandle)_objects[n];
            //                    objhandle = poh.ObjectHandle;

            //                    po = objhandle.Unwrap();

            //                    while (Marshal.ReleaseComObject(_objects[n]) != 0)
            //                        ;

            //                    _objects[n] = po;
            //                } catch { }
            //            }
            //        }
            //    }
            //}
        }

        public void Show(uint nCmdShow) {
            logger.Debug("PropertyPage Show({0})", nCmdShow);

            if (nCmdShow == 0) {
                OnPageHide();
            } else {
                OnPageShow();
            }
        }

        public void Move(ref Win32.RECT pRect) {
            logger.Debug("PropertyPage Move({0},{1},{2},{3})", pRect.Left, pRect.Right, pRect.Top, pRect.Bottom);

            OnPageMove(pRect);
        }

        public int IsPageDirty() {
            logger.Debug("PropertyPage IsPageDirty() = {0}", _isDirty);

            return _isDirty ? Win32.S_OK : Win32.S_FALSE;
        }

        public void Apply() {
            logger.Debug("PropertyPage Apply()");
            OnPageApply();
        }

        public void Help(string pszHelpDir) {
            logger.Debug("PropertyPage Help({0})", pszHelpDir);
            OnPageHelp(pszHelpDir);
        }

        public int TranslateAccelerator(ref Message pMsg) {
            //Control ctrl = ActiveControl;
            logger.Debug("PropertyPage TranslateAccelerator()");

            //if (pMsg.message == WindowsMessages.WM_KEYDOWN) {
            //    // tab
            //    if ((int)pMsg.wParam == (int)Keys.Tab) {
            //        //bool forward = Win32.G
            //    }
            //}

            return Win32.S_OK;
        }

        #endregion

        #region propected method

        protected virtual void OnPageApply(){
            _isDirty = false;
        }

        protected virtual void OnPageActivate(IntPtr hWndParent, Win32.RECT Rect, bool bModal)
        {
            _grid = new PropertyGrid();
            _grid.CreateControl();

            Win32.SetParent(_grid.Handle, hWndParent);
        }

        protected virtual void OnPageDeactivate() { }

        protected virtual void OnPageShow() {
            _grid.Visible = true;
        }

        protected virtual void OnPageHide() {
            _grid.Visible = false;
        }

        protected virtual void OnPageMove(Win32.RECT rect) { }

        protected virtual void OnPageHelp(string helpFile) { }

        #endregion

        protected bool PageActivating {
            get { return _isActivating; }
        }

        protected bool PageIsDirty {
            get { return _isDirty; }
            set { 
                _isDirty = value;

                if (_site != null) {
                    _site.OnStatusChange(_isDirty ? (uint)PropPageStatus.Dirty : (uint)PropPageStatus.Clean);
                }
            }
        }

        [ComVisible(false)]
        public enum PropPageStatus : uint {
            Dirty = 1,
            Validate = 2,
            DirtyValidate = 3,
            Clean = 4
        }

        //protected override void Dispose(bool disposing) {
        //    //base.Dispose(disposing);

        //    SetPageSite(null);
        //    SetObjects(0, null);
        //}
    }
}
